﻿//-------------------------------------------------------------------------------------------------
// <copyright file="WondrousItemSerializedForSaveLoad.cs" company="Anthony Adam">
// Copyright (c) Anthony Adam 2012. All rights reserved.
// </copyright>
//-------------------------------------------------------------------------------------------------
// ReSharper disable once CheckNamespace
namespace SuperStarRounds
{
  using System;
  using System.Runtime.Serialization;

  using Models.WondrousItemModel;
  using Models.WondrousItemModel.Template.Parts;


  /// <summary>
  /// The serializable save file class for a Wondrous Item - it includes content config information
  /// so when loaded back, the application can set the correct content config from whatever is 
  /// currently in use.
  /// </summary>
  [Serializable]
  public class WondrousItemSerializedForSaveLoad : ISerializable
  {
    #region Data to be saved
    public WondrousItem Item { get; set; } = new WondrousItem();
    #endregion

    /// <summary>
    /// Initializes a new instance of the <see cref="WondrousItemSerializedForSaveLoad"/> class.
    /// This is the base constructor.
    /// </summary>
    public WondrousItemSerializedForSaveLoad()
    {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="WondrousItemSerializedForSaveLoad"/> class.
    /// This is the serializarion interface constructor.
    /// </summary>
    /// <param name="info">Serialization info packet containing the loaded data</param>
    /// <param name="ctxt">Streaming context of the data packet</param>
    public WondrousItemSerializedForSaveLoad(SerializationInfo info, StreamingContext ctxt)
    {
      Item.Name.Name = GetStringDefaultingEmpty("itemName", info);

      for (var index = 1; index < 5; index++)
      {
        var aura = new WondrousItemAura
        {
          Strength = GetStringDefaultingEmpty($"itemAuraStrength{index}", info),
          School = GetStringDefaultingEmpty($"itemAuraSchool{index}", info),
          SubSchool = GetStringDefaultingEmpty($"itemAuraSubSchool{index}", info),
        };

        if (string.IsNullOrEmpty(aura.Strength)) continue;
        Item.AuraAndCasterLevel.Aura.Add(aura);
      }

      Item.AuraAndCasterLevel.CasterLevel = GetStringDefaultingEmpty("itemCasterLevel", info);

      Item.AutoCalcCost = GetBooleanDefaultingFalse("itemAutoCalcCost", info);

      Item.SlotPriceWeight.Slot = GetStringDefaultingEmpty("itemSlot", info);

      for (var index = 1; index < 6; index++)
      {
        var price = new WondrousItemPrice
        {
          Price = GetDecimalDefaultingZero($"itemPrice{index}", info),
          PostFix = GetStringDefaultingEmpty($"itemPrice{index}PostFix", info)
        };

        if (price.Price > 0) Item.SlotPriceWeight.Price.Add(price);

        var cost = new WondrousItemCost
        {
          Cost = GetDecimalDefaultingZero($"itemCost{index}", info),
          PostFix = GetStringDefaultingEmpty($"itemPrice{index}PostFix", info)
        };

        if (cost.Cost > 0) Item.Construction.Cost.Add(cost);
      }

      Item.SlotPriceWeight.Weight.Weight = GetStringDefaultingEmpty("itemWeight", info);
      Item.SlotPriceWeight.Weight.PostFix = GetStringDefaultingEmpty("itemWeightPostFix", info);

      Item.Description.Description = GetStringDefaultingEmpty("itemDescription", info);

      Item.Construction.Feat.Add(GetStringDefaultingEmpty("itemFeat1", info));
      Item.Construction.Feat.Add(GetStringDefaultingEmpty("itemFeat2", info));
      Item.Construction.Feat.Add(GetStringDefaultingEmpty("itemFeat3", info));

      for (var index = 1; index < 7; index++)
      {
        var spell = new WondrousItemSpell
        {
          Level = GetStringDefaultingEmpty($"itemSpell{index}Level", info),
          School = GetStringDefaultingEmpty($"itemSpell{index}School", info),
          Spell = GetStringDefaultingEmpty($"itemSpell{index}", info),
        };

        if (string.IsNullOrEmpty(spell.Level)) continue;
        Item.Construction.Spell.Add(spell);
      }

      Item.Construction.SkillRequirement.Required = GetBooleanDefaultingFalse("itemSkillReq", info);
      if (Item.Construction.SkillRequirement.Required)
      {
        Item.Construction.SkillRequirement.Ranks = GetStringDefaultingEmpty("itemSkillRanks", info);
        Item.Construction.SkillRequirement.Name = GetStringDefaultingEmpty("itemSkillName", info);
        Item.Construction.SkillRequirement.SubSkill = GetStringDefaultingEmpty("itemSubSkillName", info);
      }

      Item.Construction.RaceRequirement.Required = GetBooleanDefaultingFalse("itemRaceReq", info);
      if (Item.Construction.RaceRequirement.Required)
        Item.Construction.RaceRequirement.RaceName = GetStringDefaultingEmpty("itemRaceName", info);

      Item.Construction.OtherRequirement.Required = GetBooleanDefaultingFalse("itemOtherReq", info);
      if (Item.Construction.OtherRequirement.Required)
        Item.Construction.OtherRequirement.Other = GetStringDefaultingEmpty("itemOtherText", info);
    }

    /// <summary>
    /// Retrieves the serialized data from the context input stream.
    /// </summary>
    /// <param name="info">Serialization info packet referencing the save file</param>
    /// <param name="ctxt">Streaming context of the save file</param>
    public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
    {
      info.AddValue("itemName", Item.Name.Name);

      var index = 1;
      foreach (var aura in Item.AuraAndCasterLevel.Aura)
      {
        info.AddValue($"itemAuraStrength{index}", aura.Strength);
        info.AddValue($"itemAuraSchool{index}", aura.School);
        info.AddValue($"itemAuraSubSchool{index}", aura.SubSchool);
        index++;
      }

      info.AddValue("itemCasterLevel", Item.AuraAndCasterLevel.CasterLevel);

      info.AddValue("itemAutoCalcCost", Item.AutoCalcCost);
      info.AddValue("itemSlot", Item.SlotPriceWeight.Slot);

      index = 1;
      foreach (var price in Item.SlotPriceWeight.Price)
      {
        info.AddValue($"itemPrice{index}", price.Price);
        info.AddValue($"itemPrice{index}PostFix", price.PostFix);
        index++;
      }

      index = 1;
      foreach (var cost in Item.Construction.Cost)
      {
        info.AddValue($"itemCost{index}", cost.Cost);
        index++;
      }

      info.AddValue("itemWeight", Item.SlotPriceWeight.Weight.Weight);
      info.AddValue("itemWeightPostFix", Item.SlotPriceWeight.Weight.PostFix);

      info.AddValue("itemDescription", Item.Description.Description);

      index = 1;
      foreach (var feat in Item.Construction.Feat)
      {
        info.AddValue($"itemFeat{index}", feat);
        index++;
      }

      index = 1;
      foreach (var spell in Item.Construction.Spell)
      {
        info.AddValue($"itemSpell{index}Level", spell.Level);
        info.AddValue($"itemSpell{index}School", spell.School);
        info.AddValue($"itemSpell{index}", spell.Spell);
        index++;
      }

      info.AddValue("itemSkillReq", Item.Construction.SkillRequirement.Required);
      if (Item.Construction.SkillRequirement.Required)
      {
        info.AddValue("itemSkillRanks", Item.Construction.SkillRequirement.Ranks);
        info.AddValue("itemSkillName", Item.Construction.SkillRequirement.Name);
        info.AddValue("itemSubSkillName", Item.Construction.SkillRequirement.SubSkill);
      }

      info.AddValue("itemRaceReq", Item.Construction.RaceRequirement.Required);
      if (Item.Construction.RaceRequirement.Required)
        info.AddValue("itemRaceName", Item.Construction.RaceRequirement.RaceName);

      info.AddValue("itemOtherReq", Item.Construction.OtherRequirement.Required);
      if (Item.Construction.OtherRequirement.Required)
        info.AddValue("itemOtherText", Item.Construction.OtherRequirement.Other);
    }

    private static bool GetBooleanDefaultingFalse(string key, SerializationInfo info)
    {
      try
      {
        return info.GetBoolean(key);
      }
      catch (Exception)
      {
        return false;
      }
    }

    private static string GetStringDefaultingEmpty(string key, SerializationInfo info)
    {
      try
      {
        return info.GetString(key);
      }
      catch (Exception)
      {
        return string.Empty;
      }
    }

    private static decimal GetDecimalDefaultingZero(string key, SerializationInfo info)
    {
      try
      {
        return info.GetDecimal(key);
      }
      catch (Exception)
      {
        return 0;
      }
    }
  }
}
